<?php
declare (strict_types=1);

namespace app\service;

use think\App;
use think\facade\Db;
use app\model\FetchTaskModel;
use app\model\FetchUrlModel;
use app\model\FetchLogModel;

class TaskService extends \think\Service
{
    private $fetchTaskModel;
    const DEFAULT_LIMIT = 1000;
    const TASTK_LIFE = 120;

    function __construct(App $app, FetchTaskModel $fetchTaskModel, FetchLogModel $fetchLogModel, FetchUrlModel $fetchUrlModel)
    {
        $this->app = $app;
        $this->fetchTaskModel = $fetchTaskModel;
        $this->fetchLogModel = $fetchLogModel;
        $this->fetchUrlModel = $fetchUrlModel;
    }


    function getLimit($fetch_url_id)
    {
        $objUrl = $this->fetchUrlModel->find($fetch_url_id);
        $limit = 0;
        if ($objUrl) {
            $limit = $objUrl->limit;
        }
        if (!$limit) {
            $limit = self::DEFAULT_LIMIT;
        }
        return $limit;
    }

    /**
     * 创建新任务 对方删除数据修复,需要放在fetch_url表中,做过fix_total字段
     * @param $fetch_url_id
     * @param $remote_total
     */
    function createTask($fetch_url_id, $remote_total = 0, $table_name = '')
    {
        $rt = [];
        // step 1 获取上一次的offset
        $lastTask = $this->fetchTaskModel
            ->where('fetch_url_id', $fetch_url_id)
            ->order('fetch_offset', 'desc')
            ->find();

        // step 2 是否可以添加新任务 $noMoreFetch 表示没有更多数据
        $noMoreFetch = false;
        $new_offset = 0;
        if ($lastTask) {

            $new_offset = $lastTask['fetch_offset'] + $lastTask['fetch_limit'];
            // 已经完成,没有取到数据那么多,要修改实际 fetch_limit
            if ($lastTask['result_count'] > 0) {
                $new_offset = $lastTask['fetch_offset'] + $lastTask['result_count'];
            }

            if ($new_offset < $remote_total) {
                $new_offset = min($new_offset, $remote_total);
            }
            if ($new_offset >= $remote_total) {
                $noMoreFetch = true;
            }
        } else {
            $new_offset = Db::name($table_name)->count();
        }

        // step 3 创建新的任务
        if (!$noMoreFetch) {
            $data = [
                'fetch_url_id' => $fetch_url_id,
                'fetch_limit' => $this->getLimit($fetch_url_id),
                'fetch_offset' => $new_offset,
            ];
            $id = $this->fetchTaskModel->insertGetId($data);
            if ($id) {
                $rt = $this->fetchTaskModel->find($id)->toArray();
            }
        }
        return $rt;
    }


    /**
     * 查询失败的任务
     * @return mixed
     */
    function findFailedTask()
    {
        $rs = $this->fetchTaskModel
            ->where('finish_at', 0)
            ->where('start_at', '<', time() - self::TASTK_LIFE)
            //->where('fetch_times', '<',2)
            //->where('fetch_url_id', '<',14)  // debug?
            ->find();
        return $rs ? $rs->toArray() : [];
    }

    static function getUrl($table, $url, $sc = 'asc', $offset = 0, $limit = 1000, $extra = [])
    {
        if(is_bool(strpos($url,'?'))){
            $url = $url.'?';
        }
        $url.="&offset={$offset}&limit={$limit}&order={$sc}";

        if(is_bool(strpos($url,'sort='))){
            $url.="&sort={$table}.id";
        }
        foreach ($extra as $k => $v) {
            $url = $url . "&" . $k . "=" . $v;
        }
        return $url;
    }

    /**
     * 开始任务id 记录日志
     * @param $id
     */
    function start($id)
    {
        $objTask = $this->fetchTaskModel->find($id);
        $objUrl = $this->fetchUrlModel->find($objTask['fetch_url_id']);
        $objTask->save(['start_at' => time()]);
        $url = self::getUrl($objUrl['table_name'], $objUrl['url'],$objUrl['fetch_sort'], $objTask['fetch_offset'], $objTask['fetch_limit']);
        $logId = $this->fetchLogModel->insertGetId(['fetch_task_id' => $id, 'url' => $url, 'start_at' => time()]);

        $rt = [$logId => $url];
        return $rt;
    }

    /**
     * 完成任务,便于用于分配
     * @param $id
     * @param $result_count
     * @param $remote_total
     * @return bool
     */
    function finish($id, $result_count, $remote_total)
    {
        $data = ['finish_at' => time(),
            'result_count' => $result_count,
            'remote_total' => $remote_total
        ];
        return $this->fetchTaskModel->where(['id' => $id])->save($data);
    }
}
